package com.aspire.nm.component.miniServer.config;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.aspire.nm.component.commonUtil.constants.ConstantConfig;
import com.aspire.nm.component.miniServer.Controll;
import com.aspire.nm.component.miniServer.Filter;
import com.aspire.nm.component.miniServer.annotation.Controller;
import com.aspire.nm.component.miniServer.annotation.cls.Controllers;
import com.aspire.nm.component.miniServer.annotation.filter.FilterRequest;
import com.aspire.nm.component.miniServer.annotation.filter.FilterResponse;
import com.aspire.nm.component.miniServer.protocol.Request;
import com.aspire.nm.component.miniServer.protocol.Response;
import com.aspire.nm.component.miniServer.render.NativeRenderFactory;
import com.aspire.nm.component.miniServer.render.Render;
import com.aspire.nm.component.miniServer.render.RenderProvider;


public class Config {

    private int serverPort;
    private int corePoolSize;
    private int maximumPoolSize;
    private int workQueueSize;
    private int sessionExpireSec;
    private int resourceExpireSec;
    private String allowIpsPattern;
    private String adminAllowIpsPattern;
    private String serverEncode;
    private String clientEncode;
    private String forbiddenSourcePattern;
    private String absoluteWebappDir;
    private String renderFactoryClassName;
    private String jsonFormatErr;
    private String annotationValueConfigFile;
    private int accessLogInLine;
    
    private Render nativeRender;
    private Render customRender;
    
    
    private AnnotationConfig annotationConfig;
    
    
    
    
    
    public int getAccessLogInLine() {
        return accessLogInLine;
    }
    public void setAccessLogInLine(int accessLogInLine) {
        this.accessLogInLine = accessLogInLine;
    }
    public int getServerPort() {
        return serverPort;
    }
    public void setServerPort(int serverPort) {
        this.serverPort = serverPort;
    }
    public int getCorePoolSize() {
        return corePoolSize;
    }
    public void setCorePoolSize(int corePoolSize) {
        this.corePoolSize = corePoolSize;
    }
    public int getMaximumPoolSize() {
        return maximumPoolSize;
    }
    public void setMaximumPoolSize(int maximumPoolSize) {
        this.maximumPoolSize = maximumPoolSize;
    }
    public int getWorkQueueSize() {
        return workQueueSize;
    }
    public void setWorkQueueSize(int workQueueSize) {
        this.workQueueSize = workQueueSize;
    }
    public int getSessionExpireSec() {
        return sessionExpireSec;
    }
    public void setSessionExpireSec(int sessionExpireSec) {
        this.sessionExpireSec = sessionExpireSec;
    }
    public int getResourceExpireSec() {
        return resourceExpireSec;
    }
    public void setResourceExpireSec(int resourceExpireSec) {
        this.resourceExpireSec = resourceExpireSec;
    }
    public String getAllowIpsPattern() {
        return allowIpsPattern;
    }
    public void setAllowIpsPattern(String allowIpsPattern) {
        this.allowIpsPattern = allowIpsPattern;
    }
    public String getAdminAllowIpsPattern() {
        return adminAllowIpsPattern;
    }
    public void setAdminAllowIpsPattern(String adminAllowIpsPattern) {
        this.adminAllowIpsPattern = adminAllowIpsPattern;
    }
    public String getServerEncode() {
        return serverEncode;
    }
    public void setServerEncode(String serverEncode) {
        this.serverEncode = serverEncode;
    }
    public String getClientEncode() {
        return clientEncode;
    }
    public void setClientEncode(String clientEncode) {
        this.clientEncode = clientEncode;
    }
    public String getForbiddenSourcePattern() {
        return forbiddenSourcePattern;
    }
    public void setForbiddenSourcePattern(String forbiddenSourcePattern) {
        this.forbiddenSourcePattern = forbiddenSourcePattern;
    }
    public String getAbsoluteWebappDir() {
        return absoluteWebappDir;
    }
    public void setAbsoluteWebappDir(String absoluteWebappDir) {
        this.absoluteWebappDir = absoluteWebappDir;
    }
    public String getRenderFactoryClassName() {
        return renderFactoryClassName;
    }
    public void setRenderFactoryClassName(String renderFactoryClassName) {
        this.renderFactoryClassName = renderFactoryClassName;
    }
    public String getJsonFormatErr() {
        return jsonFormatErr;
    }
    public void setJsonFormatErr(String jsonFormatErr) {
        this.jsonFormatErr = jsonFormatErr;
    }
    public String getAnnotationValueConfigFile() {
        return annotationValueConfigFile;
    }
    public void setAnnotationValueConfigFile(String annotationValueConfigFile) {
        this.annotationValueConfigFile = annotationValueConfigFile;
    }
    public Render getNativeRender() {
        return nativeRender;
    }
    public void setNativeRender(Render nativeRender) {
        this.nativeRender = nativeRender;
    }
    public Render getCustomRender() {
        return customRender;
    }
    public void setCustomRender(Render customRender) {
        this.customRender = customRender;
    }
    public AnnotationConfig getAnnotationConfig() {
        return annotationConfig;
    }
    public void setAnnotationConfig(AnnotationConfig annotationConfig) {
        this.annotationConfig = annotationConfig;
    }
    
    public Config() throws ConfigException{

        nativeRender = new NativeRenderFactory().getRender();
        
        initConfigPath(null);
        
    }
    
    private List<Class<? extends Filter>> filterImplClasss = new ArrayList<Class<? extends Filter>>();
    @SuppressWarnings("unchecked")
    public void initfilterImplClasssNames(Set<String> filterImplClasssNames) throws ConfigException{
        try{
            if(filterImplClasssNames != null){
                for(String filterImplClasssName : filterImplClasssNames){
                    Class<?> cls = Class.forName(filterImplClasssName);
                    filterImplClasss.add((Class<? extends Filter>) cls);
                }
            }
        }
        catch(Exception e){
            throw new ConfigException(e.toString());
        }
    }
    
    private List<Class<? extends Controll>> controllImplClasss = new ArrayList<Class<? extends Controll>>();
    @SuppressWarnings("unchecked")
    public void initControllImplClasssNames(Set<String> controllImplClasssNames) throws ConfigException{
        try{
            if(controllImplClasssNames != null){
                for(String controllImplClasssName : controllImplClasssNames){
                    Class<?> cls = Class.forName(controllImplClasssName);
                    controllImplClasss.add((Class<? extends Controll>) cls);
                }
            }
        }
        catch(Exception e){
            throw new ConfigException(e.toString());
        }
    }
    private String configPath;
    public void initConfigPath(String configPath) throws ConfigException{
        this.configPath = configPath;
        try{
            serverPort = Integer.parseInt(get("serverPort"));
            
            corePoolSize = Integer.parseInt(get("corePoolSize"));
            maximumPoolSize = Integer.parseInt(get("maximumPoolSize"));
            workQueueSize = Integer.parseInt(get("workQueueSize"));

            sessionExpireSec = Integer.parseInt(get("sessionExpireSec"));
            resourceExpireSec = Integer.parseInt(get("resourceExpireSec"));
            
            absoluteWebappDir = get("absoluteWebappDir");
            
            forbiddenSourcePattern = get("forbiddenSourcePattern");
            allowIpsPattern = get("allowIpsPattern");
            adminAllowIpsPattern = get("adminAllowIpsPattern");
            
            clientEncode = get("clientEncode");
            serverEncode = get("serverEncode");
            
            renderFactoryClassName = get("renderFactoryClassName");
            
            jsonFormatErr = get("jsonFormatErr");
            
            annotationValueConfigFile = get("annotationValueConfigFile");
            accessLogInLine = Integer.parseInt(get("accessLogInLine"));
        }catch(Exception e){
            throw new ConfigException(e.toString());
        }
        
        
        try {
            customRender = ((RenderProvider)(Class.forName(renderFactoryClassName).newInstance())).getRender();
        } catch (InstantiationException e) {
            throw new ConfigException("can not newInstance by " + renderFactoryClassName+e);
        } catch (IllegalAccessException e) {
            throw new ConfigException("can not newInstance by " + renderFactoryClassName+e);
        } catch (ClassNotFoundException e) {
            throw new ConfigException("can not newInstance by " + renderFactoryClassName+e);
        }
    }
    
    
    public void initAnnotationConfig() throws ConfigException{
        
        annotationConfig = new AnnotationConfig(this);
        for(Class<? extends Controll> controllImplClass : controllImplClasss){
            Controllers controllers = controllImplClass.getAnnotation(Controllers.class);
            if(controllers == null) {
                annotationConfig.put(controllImplClass.getName(), "timeOut", 0);
                annotationConfig.put(controllImplClass.getName(), "path", "");
                annotationConfig.put(controllImplClass.getName(), "allowIpsPattern", "");
                annotationConfig.put(controllImplClass.getName(), "methodType", Controllers.MethodType.BOTH);
            }else{
                if(controllers.timeOut() < 0) throw new ConfigException("Controllers anntation 's timeout must > 0");
                annotationConfig.put(controllImplClass.getName(), "timeOut", controllers.timeOut());
                annotationConfig.put(controllImplClass.getName(), "path", controllers.path());
                annotationConfig.put(controllImplClass.getName(), "allowIpsPattern", controllers.allowIpsPattern());
                annotationConfig.put(controllImplClass.getName(), "methodType", controllers.methodType());
            }
        }
    }
    
    public String get(String key) {
        String defaultValue = DefaultDefine.getDefault(key);
        if(configPath == null){
            return defaultValue;
        }
        String value = ConstantConfig.getPropertiesValue(configPath,key);
        if(value == null){
            return defaultValue;
        }else{
            return value;
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    public List<Controll> getControllImpls(boolean verify) throws ConfigException{
        List<Controll> controllImpls = new ArrayList<Controll>();
        for(Class<? extends Controll> controllImplClass : controllImplClasss){
            try {
                controllImpls.add(controllImplClass.newInstance());
            } catch (InstantiationException e) {
                throw new ConfigException(controllImplClass.getName() +" can not newInstance !" + e);
            } catch (IllegalAccessException e) {
                throw new ConfigException(controllImplClass.getName() +" can not newInstance !" + e);
            }
        }
        if(verify){
            for(Controll controllImpl : controllImpls){
                Method[] methods = controllImpl.getClass().getDeclaredMethods();
                for(Method method:methods){
                    if (method.isAnnotationPresent(Controller.class)) {
                        Controller annotation = method.getAnnotation(Controller.class);
                        if(annotation.cacheTime() < 0){
                            throw new ConfigException("can not get cacheTime with ," + annotation.cacheTime());
                        }
                        if(annotation.timeOut() < 0){
                            throw new ConfigException("can not get timeout with ," + annotation.timeOut());
                        }
                    }
                }
            }
        }
        return controllImpls;
    }
    
    public List<Filter> getFilterImpls(boolean verify) throws ConfigException{
        List<Filter> filterImpls = new ArrayList<Filter>();
        for(Class<? extends Filter> filterImplClass : filterImplClasss){
            try {
                filterImpls.add(filterImplClass.newInstance());
            } catch (InstantiationException e) {
                throw new ConfigException(filterImplClass.getName() +" can not newInstance !" + e);
            } catch (IllegalAccessException e) {
                throw new ConfigException(filterImplClass.getName() +" can not newInstance !" + e);
            }
        }
        
        if(verify){
            for(Filter filterImpl : filterImpls){
                Method[] methods = filterImpl.getClass().getDeclaredMethods();
                for(Method method:methods){
                    if (method.isAnnotationPresent(FilterRequest.class)) {
                        if(method.getParameterTypes().length != 1 || method.getParameterTypes()[0] != Request.class){
                            throw new ConfigException("method " + method.getName() +" with annotation FilterRequest parameter must 1 and type must be com.aspire.nm.component.miniServer.http.Request");
                        }
                    }
                    if (method.isAnnotationPresent(FilterResponse.class)) {
                        if(method.getParameterTypes().length != 1 || method.getParameterTypes()[0] != Response.class){
                            throw new ConfigException("method " + method.getName() +" with annotation FilterResponse parameter must 1 and type must be com.aspire.nm.component.miniServer.http.Response");
                        }
                    }
                }
            }
        }
        
        return filterImpls;
    }


    
    
    
    
    
    
    
    
    
    
    
    
    
}
